﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DotSpatial.Data;
using DotSpatial.Topology;
using DotSpatial.Projections;
//using System.Windows.Forms;


namespace GeostatisticalTool.Classes
{
    public abstract class AbstractInterpolator:DataSourceInterpolators
    {

        public string method = "";

        public AbstractInterpolator(IFeatureSet shapeLayer, int idField):
            base(shapeLayer,idField)
        {
        }


        public string GetMethodName()
        {
            return this.method;
        }


        /// <summary>Gets a value indicating number of point in the Shapefile</summary> 
        public int NumPoints
        {
            get { return this.npoints; }
        }

        /// <summary>Gets a value indicating number of points used by search</summary> 
        public int Np
        {
            get { return this.np; }
        }

        

        /// <summary>
        /// This function creates the HDR of Gridfile
        /// </summary>
        /// <param name="inExtents"> Extension of grid</param>
        /// <param name="cellSize">Size cell of the grid</param>
        /// <param name="projection">Projection (the same that shapefile)</param>
        /// <param name="noDataValue">No value definition</param>
        /// <param name="outGridPath">Path of the output</param>
        /// <param name="outGrid">Name of the output grid</param>
        public static void CreateGridFromExtents(
            Extent inExtents, double cellSize, ProjectionInfo projection, double noDataValue, string outGridPath, out IRaster outGrid)
        {

            double height = Math.Abs(inExtents.MaxY - inExtents.MinY) ;
            double width = Math.Abs(inExtents.MaxX - inExtents.MinX) ;
            int numberRows = Convert.ToInt32(Math.Ceiling(height / cellSize))+1;
            int numberCols = Convert.ToInt32(Math.Ceiling(width / cellSize))+1;

            // outGrid = Raster.CreateRaster(@outGridPath, null, demRaster.NumColumns, demRaster.NumRows, 1, demRaster.DataType, rasterOptions);
            outGrid = Raster.CreateRaster(@outGridPath, null, numberCols, numberRows, 1, typeof(float), new String[] { });
            outGrid.NoDataValue = noDataValue;
            outGrid.Projection = projection;
            outGrid.CellHeight = cellSize;
            outGrid.CellWidth = cellSize;
            //if (inExtents.MinX < 0)
            //    outGrid.Xllcenter = inExtents.MinX + (cellSize / 2.0);
            //else
            outGrid.Xllcenter = inExtents.MinX;// -(cellSize / 2.0);

            //if (inExtents.MinY < 0)
            //    outGrid.Yllcenter = inExtents.MinY + (cellSize / 2.0);
            //else
            outGrid.Yllcenter = inExtents.MinY;// -(cellSize / 2.0);
        }

        public IRaster Surface(DotSpatial.Data.Extent inExtents, double cellSize, DotSpatial.Projections.ProjectionInfo projection, double noDataValue, string outGridPath)
        {

            IRaster raster;
           // this.np=this.Search.MaxNumPoints;
            CreateGridFromExtents(inExtents, cellSize, projection, noDataValue, outGridPath, out raster);

            int nr = raster.NumRows;
            int nc = raster.NumColumns;

            for (int row = 0; row < nr; row++)
            {
                for (int col = 0; col < nc; col++)
                {
                   Coordinate cor = GetXYCell(raster, col, row);
                    double val = this.Interpolate( cor.X, cor.Y, cor.Z,true)[0];
                    raster.Value[row,col] = val;
                }
            }
            raster.Save();
            raster.Close();
            return raster;
        }

        public IRaster Surface(DotSpatial.Data.IRaster mask,DotSpatial.Data.Extent inExtents, double cellSize, DotSpatial.Projections.ProjectionInfo projection, double noDataValue, string outGridPath)
        {

            IRaster raster;
            // this.np=this.Search.MaxNumPoints;
            CreateGridFromExtents(inExtents, cellSize, projection, noDataValue, outGridPath, out raster);

            int nr = raster.NumRows;
            int nc = raster.NumColumns;

            for (int row = 0; row < nr; row++)
            {
                for (int col = 0; col < nc; col++)
                {
                    if (mask.Value[row, col] == 1)
                    {
                        Coordinate cor = GetXYCell(raster, col, row);
                        double val = this.Interpolate(cor.X, cor.Y,cor.Z, true)[0];
                        raster.Value[row, col] = val;
                    }
                    else
                        raster.Value[row, col] = noDataValue;
                }
            }
            raster.Save();
            raster.Close();
            return raster;
        }

        public Coordinate GetXYCell(IRaster raster,int col,int row)
        {
            double xmin = raster.Xllcenter;
            double ymin = raster.Yllcenter;
            double cell = raster.CellWidth;
            int numColumns = raster.NumColumns;
            int numRows = raster.NumRows;

            double y = ((numRows - row) * cell) + ymin;
            double x = (col * cell) + xmin;
            return new Coordinate(x, y);
        }

        public abstract double[] Interpolate(double x, double y, double z, bool include);

        public abstract double[] CrossValidation();

        public  ParameterInterpolator GetParameters()
        {
            return null;
        }

        public void SetParameters(ParameterInterpolator parameters)
        {
            return;
        }
        public double[] GetMaxValuesZ()
        {
            return this.extentZ;
        }

        #region temporal
       
        //public double[] CrossValidation(int nPn,double standardDev)
        //{ 
        //    this.np=nPn;
        //    double[] output;
 
        //    if (this.method == "Kriging")
        //        output = new double[5];
        //    else
        //       output = new double[1];
            

        //    double SSerror = 0;

        //    double sumAllValues = 0;
        //    double quad = 0; ;

        //    for (int i = 0; i < this.NumPoints; i++)
        //    {
        //        this.cpoints[i, 3] = this.Interpolate(nPn, this.cpoints[i, 0], this.cpoints[i, 1]);
        //        this.cpoints[i, 5] = this.cpoints[i, 2] - this.cpoints[i, 3];

        //        sumAllValues += this.cpoints[i, 3];
        //        quad += (this.cpoints[i, 3] * this.cpoints[i, 3]);

        //        SSerror += (this.cpoints[i, 5] * this.cpoints[i, 5]);
        //    }
        //    double mean = sumAllValues / this.NumPoints;
        //    double SStotal = (quad - (2 * sumAllValues * mean) + (this.NumPoints * mean * mean))/ (this.NumPoints*mean) ;

        //    output[0] = SStotal;

        //       //Math.Sqrt(SStotal / (this.NumPoints-1)); 

        //    return output;
        //}
        #endregion

    
    }
}
